package com.yungu.swift.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * @author Zerrion
 */
public class Md5Utils {

    private static final Logger logger = LoggerFactory.getLogger(Md5Utils.class);

    private static char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};

    private static ThreadLocal<MessageDigest> digestThreadLocal = new ThreadLocal<MessageDigest>() {

        @Override
        protected MessageDigest initialValue() {
            try {
                return MessageDigest.getInstance("MD5");
            } catch (NoSuchAlgorithmException nsaex) {
                logger.error("Md5Utils 初始化失败，MessageDigest 不支持 MD5", nsaex);
            }
            return null;
        }
    };

    private Md5Utils() {
    }

    /**
     * 生成字符串的 Md5 校验值
     *
     * @param str
     * @return
     */
    public static String encode(String str) {
        return encode(str.getBytes());
    }
    /**
     * 生成字符串的 Md5 校验值
     *
     * @param str
     * @return
     */
    public static String encode(String str,String charset) {
        try {
            byte[] bytes = str.getBytes(charset);
            return encode(bytes);
        }catch (Exception e){
            return "";
        }
    }

    /**
     * 生成文件流的 Md5 校验值
     *
     * @param inputStream
     * @return
     * @throws IOException
     */
    public static String encode(InputStream inputStream) {
        MessageDigest messageDigest = digestThreadLocal.get();
        messageDigest.reset();
        byte[] buffer = new byte[1024];
        int numRead;
        try {
            while ((numRead = inputStream.read(buffer)) > 0) {
                messageDigest.update(buffer, 0, numRead);
            }
        } catch (IOException e) {
            logger.error("Md5Utils encode inputStream read error", e);
        } finally {
            try {
                inputStream.close();
            } catch (IOException e) {
                logger.error("Md5Utils encode inputStream close error", e);
            }
        }
        return bufferToHex(messageDigest.digest());
    }


    public static String encode(byte[] bytes) {
        MessageDigest messageDigest = digestThreadLocal.get();
        messageDigest.reset();
        messageDigest.update(bytes);
        return bufferToHex(messageDigest.digest());
    }

    private static String bufferToHex(byte[] bytes) {
        return bufferToHex(bytes, 0, bytes.length);
    }

    private static String bufferToHex(byte[] bytes, int m, int n) {
        StringBuffer stringbuffer = new StringBuffer(2 * n);
        int k = m + n;
        for (int l = m; l < k; l++) {
            appendHexPair(bytes[l], stringbuffer);
        }
        return stringbuffer.toString().toUpperCase();
    }

    private static void appendHexPair(byte bt, StringBuffer stringbuffer) {
        // 取字节中高 4 位的数字转换, >>>
        char c0 = HEX_DIGITS[(bt & 0xf0) >> 4];
        // 为逻辑右移，将符号位一起右移,此处未发现两种符号有何不同
        // 取字节中低 4 位的数字转换
        char c1 = HEX_DIGITS[bt & 0xf];
        stringbuffer.append(c0);
        stringbuffer.append(c1);
    }
}
